
/**		
 * 
 *	uk.co.lmfm.guppy.model.EclipseProxy
 *	
 *	@version 1.00 | Jan 18, 2010
 *	@author Justin Windle
 *  
 **/
 
package uk.co.lmfm.guppy.model 
{
	import uk.co.lmfm.guppy.model.vo.ClassLibraryVO;
	import uk.co.lmfm.guppy.model.vo.ProjectVO;
	import uk.co.lmfm.util.FileUtil;
	import uk.co.lmfm.util.StringUtil;

	import org.osflash.thunderbolt.Logger;
	import org.puremvc.as3.multicore.interfaces.IProxy;
	import org.puremvc.as3.multicore.patterns.proxy.Proxy;

	import flash.display.Sprite;
	import flash.events.FileListEvent;
	import flash.filesystem.File;
	import flash.utils.Dictionary;
	import flash.utils.getQualifiedClassName;

	/**
	 * EclipseProxy
	 */
	public class EclipseProxy extends Proxy implements IProxy 
	{
		//	----------------------------------------------------------------
		//	CONSTANTS
		//	----------------------------------------------------------------

		public static const NAME : String = "EclipseProxy";
		public static const PREFS_PATH : String = "/configuration/.settings/org.eclipse.ui.ide.prefs";		public static const FDT_CORE_PREFS_PATH : String = ".settings/com.powerflasher.fdt.core.prefs";

		private static const IGNORE : Array = [".svn"];
		private static const SRC_PATH : String = "src";		private static const LIB_PATH : String = "lib";		private static const SRC_LIB_PATH : String = "src-lib";		private static const BIN_DEBUG_PATH : String = "bin-debug";		private static const BIN_DEPLOY_PATH : String = "bin-deploy";		private static const CODE_LIBRARIES_PATH : String = "AS3";		private static const PURE_MVC_PATH : String = "FDT/templates/project/MVC";		private static const BUILD_PROPERTIES_PATH : String = "build.properties";		private static const BUILD_XML_PATH : String = "build.xml";		private static const CLASS_TEMPLATE : String = "FDT/templates/code/Class.as";		private static const DOT_PROJECT_PATH : String = ".project";

		//	----------------------------------------------------------------
		//	PRIVATE MEMBERS
		//	----------------------------------------------------------------

		private var _basePaths : Dictionary;
		private var _targetPaths : Dictionary;
		private var _project : ProjectVO;
		private var _library : File;
		private var _searches : int;

		//	----------------------------------------------------------------
		//	CONSTRUCTOR
		//	----------------------------------------------------------------

		public function EclipseProxy(data : Object = null)
		{
			super(NAME, data);
		}

		//	----------------------------------------------------------------
		//	PUBLIC METHODS
		//	----------------------------------------------------------------

		public function addWorkspacePath(workspacePath : String, eclipsePath : String) : void
		{
			var prefs : File = new File();
			prefs = prefs.resolvePath(eclipsePath).resolvePath(PREFS_PATH);
			
			if(prefs.exists)
			{
				var data : String = FileUtil.readUTF(prefs);
				data = data.replace(/(\bRECENT_WORKSPACES=)(.*)/ig, '$1' + workspacePath + '\\n$2');
				
				Logger.info("Added workspace path to Eclipse: " + workspacePath);
				
				FileUtil.writeUTF(data, prefs);
			}
			else
			{
				Logger.error("Cannot find Eclipse prefs file at: " + eclipsePath + EclipseProxy.PREFS_PATH);
			}
		}

		public function createProject(project : ProjectVO, libraryPath : String) : void
		{
			if(project.folder.resolvePath(DOT_PROJECT_PATH).exists)
			{
				Logger.error("Project folder already exists, are you sure yu want to overwrite?");
				return;
			}
			
			_project = project;
			_library = new File().resolvePath(libraryPath);
			
			createProjectStructure();
		}

		//	----------------------------------------------------------------
		//	PRIVATE METHODS
		//	----------------------------------------------------------------

		private function createProjectStructure() : void
		{
			_searches = 0;
			
			_basePaths = new Dictionary();
			_targetPaths = new Dictionary();
			
			// Copy base template

			var template : File = _library.resolvePath(_project.playerVersion.template.path);
			var src_lib : File = _project.folder.resolvePath(SRC_LIB_PATH);
						
			copyDirectoryContents(template, _project.folder, template.nativePath);
			
			// Create empty dirs

			// TODO update build files to use bin-debug / bin-deploy

			_project.folder.resolvePath(BIN_DEBUG_PATH).createDirectory();			_project.folder.resolvePath(BIN_DEPLOY_PATH).createDirectory();
						_project.folder.resolvePath(SRC_PATH).createDirectory();			_project.folder.resolvePath(SRC_LIB_PATH).createDirectory();
						_project.folder.resolvePath(LIB_PATH).createDirectory();			_project.folder.resolvePath(LIB_PATH).resolvePath("fla").createDirectory();
			_project.folder.resolvePath(LIB_PATH).resolvePath("swc").createDirectory();
			
			// Copy libraries
			
			for each (var lib : ClassLibraryVO in _project.libraries) 
			{
				var classpath : File = _library.resolvePath(CODE_LIBRARIES_PATH).resolvePath(lib.path);
				copyDirectoryContents(classpath, src_lib, classpath.nativePath);
			}
			
			// Create package structure

			var src : File = _project.folder.resolvePath(SRC_PATH);
			var nsComponents : Array = _project.rootPackage.split('.');
			
			for (var i : int = 0;i < nsComponents.length;i++)
			{
				src = src.resolvePath(nsComponents[i]);
			}
			
			// Pure MVC

			if(_project.isPureMVC)
			{
				var mvcTemplate : File = _library.resolvePath(PURE_MVC_PATH);
				var mvcPath : File = _project.folder.resolvePath(SRC_PATH).resolvePath(nsComponents.join("/"));
				copyDirectoryContents(mvcTemplate, mvcPath, mvcTemplate.nativePath);
			}
		}

		/**
		 * Called once async directory merge is complete
		 * @see onDirectoryListing
		 */

		private function configureProject() : void
		{
			// Configure build file

			var buildFile : File = _project.folder.resolvePath(BUILD_XML_PATH);
			var build : String = FileUtil.readUTF(buildFile);
			
			build = build.replace(/\${project.name}/g, _project.name);
			
			FileUtil.writeUTF(build, buildFile);
			
			// Configure build props

			var buildProps : File = _project.folder.resolvePath(BUILD_PROPERTIES_PATH);
			var props : String = FileUtil.readUTF(buildProps);
			
			props = props.replace(/\${project.name}/g, _project.name);			props = props.replace(/\${project.class}/g, StringUtil.classToFilepath(_project.rootPackage + (_project.rootPackage.length > 0 ? "." : '') + _project.mainClass));
			props = props.replace(/\${project.sdk.path}/g, "${" + _project.playerVersion.corelib.sdk.ant + "}");
			
			FileUtil.writeUTF(props, buildProps);
			
			// Configure project file

			var projectFile : File = _project.folder.resolvePath(DOT_PROJECT_PATH);
			var project : String = FileUtil.readUTF(projectFile);
			
			project = project.replace(/\${project.sdk.path}/g, _project.playerVersion.corelib.path);
			
			FileUtil.writeUTF(project, projectFile);
			
			// Configure fdt prefs file

			var fdtPrefsFile : File = _project.folder.resolvePath(FDT_CORE_PREFS_PATH);
			var fdtPrefs : String = FileUtil.readUTF(fdtPrefsFile);
			
			fdtPrefs = fdtPrefs.replace(/\${project.sdk.name}/g, _project.playerVersion.corelib.name);
			
			FileUtil.writeUTF(fdtPrefs, fdtPrefsFile);
			
			// Create the base class

			var docClass : File;
			
			if(_project.isPureMVC)
			{
				// TODO add Pure specific class
				docClass = makeClass(_project.mainClass, _project.rootPackage, _project.folder.resolvePath(SRC_PATH), _project.author, Sprite);
				FileUtil.writeUTF(FileUtil.readUTF(docClass) + "\n\n// Pure MVC Class", docClass);
			}
			else
			{
				docClass = makeClass(_project.mainClass, _project.rootPackage, _project.folder.resolvePath(SRC_PATH), _project.author, Sprite);				
			}
			
			// TODO Add project to workspace?
		}

		private function makeClass(filename : String, rootPackage : String, srcFolder : File, author : String, baseClass : Class = null) : File
		{
			var classTemplate : File = _library.resolvePath(CLASS_TEMPLATE);
			var classText : String = FileUtil.readUTF(classTemplate);
			
			var imports : String = '';
			var extend : String = '';
			var date : Array = String(new Date()).split(' ');
			
			if(baseClass)
			{
				imports += "import " + getQualifiedClassName(baseClass).replace(/::/g, '.') + ";\n";
				extend = "extends " + getQualifiedClassName(baseClass).match(/\w{1,}$/g)[0];
			}
		
			classText = classText
							.replace(/\${rootPackage}/g, rootPackage)
							.replace(/\${optionalDot}/g, rootPackage.length > 0 ? '.' : '')
							.replace(/\${className}/g, filename.replace(/(.*).as$/g, '$1'))
							.replace(/\${fileName}/g, filename)							.replace(/\${author}/g, author)							.replace(/\${imports}/g, imports)							.replace(/\${extend}/g, extend)
							.replace(/\${date}/g, date[2] + ' ' + date[1] + ', ' + date[5]);

			var docClass : File = srcFolder
										.resolvePath(rootPackage.replace(/\./g, '/'))
										.resolvePath(filename);
										
			FileUtil.writeUTF(classText, docClass);
			
			return docClass;
		}

		private function copyDirectoryContents(dir : File, target : File, base : String) : void
		{
			if(IGNORE.indexOf(dir.name) < 0)
			{
				_basePaths[dir] = base;
				_targetPaths[dir] = target;
				
				_searches++;
				
				dir.addEventListener(FileListEvent.DIRECTORY_LISTING, onDirectoryListing);
				dir.getDirectoryListingAsync();
			}
		}

		//	----------------------------------------------------------------
		//	EVENT HANDLERS
		//	----------------------------------------------------------------

		private function onDirectoryListing(event : FileListEvent) : void
		{
			var base : String = _basePaths[event.currentTarget];
			var target : File = _targetPaths[event.currentTarget];
			
			for each (var item : File in event.files) 
			{
				var path : String = item.nativePath.substr(base.length + 1);
				var file : File = target.resolvePath(path);
					
				if(item.isDirectory)
				{
					if(!file.exists && IGNORE.indexOf(file.name) < 0)
					{
						file.createDirectory();
					}
					
					copyDirectoryContents(item, target, base);
				}
				else
				{
					item.copyTo(file, true);
				}
			}
			
			_searches--;
			
			if(_searches < 1)
			{
				configureProject();
			}
		}
	}
}
